package com.xcity.tools.http;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;
import com.xcity.Server;
import com.xcity.game.battle.pve.template.StageTemplate;
import com.xcity.game.employee.template.EmployeeComboTemplate;
import com.xcity.game.employee.template.EmployeeQualityUpTemplate;
import com.xcity.game.employee.template.EmployeeTemplate;
import com.xcity.tools.http.HttpService.SheetField;
import com.xcity.tools.http.HttpService.SheetStruct;
import com.xcity.tools.http.HttpService.XlsKey;
import com.xcity.tools.http.HttpService.XlsStruct;
import com.xcity.tools.http.impl.EmployeeComboTemplateFilter;
import com.xcity.tools.http.impl.EmployeeQualityUpTemplateFilter;
import com.xcity.tools.http.impl.EmployeeTemplateFilter;
import com.xcity.tools.http.impl.StageTemplateFilter;
import com.xcity.tools.http.template.MenuOpenTemplate;
import com.xcity.tools.template.TemplateClassCreater;
import com.xcity.tools.template.TemplateClassCreater.Head;

import naga.x.App;
import naga.x.common.Config;
import naga.x.game.template.Template;
import naga.x.game.template.TemplateParser;
import naga.x.game.template.TemplateService;
import naga.x.game.template.annotation.Excel;
import naga.x.util.IOUtils;
import naga.x.util.StringUtils;

/**
 * separate from {@HttpService}
 * @author shipeng.zhu
 */
@Configuration
@EnableAutoConfiguration
@ConfigurationProperties(locations = "classpath:httpxls.properties")
public class HttpXLSTools implements InitializingBean{

	private String dataDir;
	
	public String getDataDir() {
		return dataDir;
	}
	public void setDataDir(String dataDir) {
		this.dataDir = dataDir;
	}

	Map<XlsKey, Class<? extends Template>> templateClasses = new LinkedHashMap<>(); // key: xls-sheet
	List<XlsStruct> templateStructs = new ArrayList<>();
	TemplateService service = new TemplateService();
	String html;
	Map<Class<? extends Template>, XLS2JSONFilter<? extends Template>> filters = new LinkedHashMap<>();

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println(dataDir);
		init();
	}
	
	void init(){
		JSON.DEFAULT_GENERATE_FEATURE = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteEnumUsingToString, false);
		JSON.DEFAULT_GENERATE_FEATURE = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteEnumUsingName, false);
		JSON.DEFAULT_GENERATE_FEATURE = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.PrettyFormat, true);
		TypeUtils.compatibleWithJavaBean = true;
		
		App.getApp().setConfig(new Config());
		App.getApp().getServiceManager().add(service);
//			App.getApp().getConfig().put(Config.DATA_DIR, DIR_XLS);
		App.getApp().getConfig().dataDir = dataDir;
		initFilters();
		registerTemplates();
		readTemplatesStruct();
		readHtml();
	}

	void initFilters() {
		filters.put(EmployeeTemplate.class, new EmployeeTemplateFilter());
		filters.put(EmployeeQualityUpTemplate.class, new EmployeeQualityUpTemplateFilter());
		filters.put(StageTemplate.class, new StageTemplateFilter());
		filters.put(EmployeeComboTemplate.class, new EmployeeComboTemplateFilter());
	}
	
	void readHtml() {
		html = IOUtils.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("xls2json.html"));
	}
	void registerTemplates() {
		try {
			Method method = Server.class.getDeclaredMethod("registerTemplates");
			method.setAccessible(true);
			method.invoke(null);
			registerUserDefinedTemplates();
			
			Field field = TemplateService.class.getDeclaredField("registeredTemplateClasses");
			field.setAccessible(true);
			Set<Class<? extends Template>> classes = (Set<Class<? extends Template>>) field.get(null);
			TemplateParser parser = new TemplateParser(service);
			for (Class<? extends Template> cls : classes) {
				System.out.println("parse try:" + cls);
				Excel anno = cls.getDeclaredAnnotation(Excel.class);
				if (!anno.isStatic()) {
					File xls = new File(dataDir, anno.value());
					Workbook workbook;
					if (xls.getName().endsWith(".xlsx")) {
						workbook = new XSSFWorkbook(xls);
					} else {
						workbook = new HSSFWorkbook(new FileInputStream(xls));
					}
					Sheet sheet = StringUtils.isNotEmpty(anno.sheetName()) ? workbook.getSheet(anno.sheetName()) : workbook.getSheetAt(anno.sheet());
					XlsKey key = new XlsKey(anno.value(), sheet.getSheetName());
					templateClasses.put(key, cls);
					workbook.close();
					
					parser.parse(cls);
				}
				System.out.println("parse ok:" + cls);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	Class<? extends Template> getTemplateClass(String xls, String sheet) {
		return templateClasses.get(new XlsKey(xls, sheet));
	}

	void readTemplatesStruct() {
		try {
//			Set<XlsKey> set = templateClasses.keySet();
			Set<Entry<XlsKey, Class<? extends Template>>> set = templateClasses.entrySet();
			for (Entry<XlsKey, Class<? extends Template>> entry : set) {
				XlsKey xk = entry.getKey();
				TemplateClassCreater.SHEET = -1;
				TemplateClassCreater.SHEET_NAME = xk.sheet;
				Workbook wb = TemplateClassCreater.getWorkbook(new File(dataDir, xk.xls));
				List<Head> heads = TemplateClassCreater.readHead(wb);
				
				XlsStruct struct = find(xk.xls);
				SheetStruct sheetStruct = new SheetStruct(TemplateClassCreater.sheetIndex, TemplateClassCreater.sheetName);
				XLS2JSONFilter<? extends Template> filter = filters.get(entry.getValue());
				List<SheetField> fields = filter != null ? filter.getFields() : null;
				if (fields != null) {
					sheetStruct.fields = fields;
				} else {
					for (Head head : heads) {
						SheetField sf = new SheetField(head.name, head.desc);
						if (StringUtils.isNotEmpty(head.name) && !sheetStruct.fields.contains(sf)) {
							sheetStruct.fields.add(sf);
						}
					}
				}
				struct.sheets.add(sheetStruct);
			}
			for (XlsStruct struct : templateStructs) {
				Collections.sort(struct.sheets);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	XlsStruct find(String xls) {
		List<XlsStruct> list = templateStructs;
		for (int i = list.size() - 1; i >= 0; i--) {
			XlsStruct xs = list.get(i);
			if (xls.equals(xs.name)) {
				return xs;
			}
		}
		XlsStruct xs = new XlsStruct(xls);
		list.add(xs);
		return xs;
	}

	void registerUserDefinedTemplates() {
		TemplateService.register(MenuOpenTemplate.class);
		TemplateService.register(EmployeeComboTemplate.class);
	}
	
	public String tryGetHtml(){
		return html;
	}
	
	public TemplateService tryGetService(){
		return service;
	}
	
	public Map<Class<? extends Template>, XLS2JSONFilter<? extends Template>> tryGetFilters(){
		return filters;
	}
	
	public List<XlsStruct> tryGetTemplateStructs(){
		return templateStructs;
	}
}
